package front

import (
	jwtgo "github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	red "github.com/gomodule/redigo/redis"
	"github.com/juju/errors"
	"log"
	"net/http"
	"qihuang/db/redis"
	"qihuang/helper"
	"qihuang/loger"
	myjwt "qihuang/middleware"
	_ "qihuang/model"
	_ "qihuang/protocol"
	"qihuang/service/front"
	"regexp"
	"strconv"
	"time"
)

type Users struct {
}

// 注册信息
type RegisterInfo struct {
	// 手机号
	Phone string `json:"phone"`
	// 密码
	Password string `json:"password"`
}

type LoginResult struct {
	Token    string `json:"token"`
	Avatar   string `json:"avatar"`
	City     string `json:"city"`
	Country  string `json:"country"`
	FamilyId int    `json:"family_id"`
	Gender   string `json:"gender"`
	Phone    string `json:"phone"`
	Status   int    `json:"status"`
	Summary  string `json:"summary"`
	Username string `json:"username"`
}

//mobile verify
func VerifyMobileFormat(mobileNum string) bool {
	//regular := "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$"
	regular := "^1\\d{10}$"
	reg := regexp.MustCompile(regular)
	return reg.MatchString(mobileNum)
}

func VerifyCodeFormat(codeNum string) bool {
	regular := "^\\d{6}$"
	reg := regexp.MustCompile(regular)
	return reg.MatchString(codeNum)
}

func VerifyInviteCodeFormat(codeNum string) bool {
	regular := "^[A-Za-z0-9]{6}$"
	reg := regexp.MustCompile(regular)
	return reg.MatchString(codeNum)
}

//mobile verify
func VerifyPwdFormat(pwd string) bool {
	// 至少包含数字跟字母，可以有字符，长度6-20
	regular := "^(?:\\d|[a-zA-Z]|[!@#$%^&*]){6,18}$"
	reg := regexp.MustCompile(regular)
	return reg.MatchString(pwd)
}

func (Users) SendCode(c *gin.Context) {
	//phone := c.PostForm("phone")
	phone := c.DefaultQuery("phone", "")
	res := VerifyMobileFormat(phone)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "请输入合法手机号。",
		})
		return
	}
	_, res = front.CheckUser(phone)
	if res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "账号已存在，您可直接登陆访问。",
		})
		return
	}
	code := helper.GenValidateCode(6)
	redisConn := redis.RedisClient.Pool.Get()
	cacheKey := "phone_code_" + phone
	if err := redisConn.Err(); err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "解析数据失败！",
		})
		return
	}
	redisConn.Do("set", cacheKey, code)
	redisConn.Do("expire", cacheKey, 10*60)
	//res = helper.SendAliSms(code, phone)
	res = helper.SendQiNiuSms(code, phone)
	if res {
		c.JSON(http.StatusOK, gin.H{
			"status": 0,
			"msg":    "验证码发送成功！",
		})
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "验证码发送失败！",
		})
	}
	return
}

//注册
func (Users) Register(c *gin.Context) {
	phone := c.PostForm("phone")
	code := c.PostForm("code")
	password := c.PostForm("password")
	invitationCode := c.PostForm("invitation")

	if code == "" {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "验证码不能为空。",
		})
		return
	}
	if phone == "" {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "手机号不能为空。",
		})
		return
	}
	if password == "" {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "密码不能为空。",
		})
		return
	}
	res := VerifyMobileFormat(phone)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "请输入合法手机号。",
		})
		return
	}
	res = VerifyPwdFormat(password)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "密码不合法！",
		})
		return
	}
	res = VerifyCodeFormat(code)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "验证码不正确！",
		})
		return
	}
	res = VerifyInviteCodeFormat(invitationCode)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "邀请码不正确！",
		})
		return
	}
	redisConn := redis.RedisClient.Pool.Get()
	cacheKey := "phone_code_" + phone
	if err := redisConn.Err(); err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "解析数据失败！",
		})
		return
	}
	registerCode, err := red.String(redisConn.Do("GET", cacheKey))
	if err != nil {
		if registerCode == "" {
			loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
			c.JSON(http.StatusOK, gin.H{
				"status": 1,
				"msg":    "验证码无效！",
			})
			return
		}
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "解析数据失败！",
		})
		return
	} else {
		if registerCode != "" {
			parseCode, err := strconv.Atoi(code)
			if err != nil {
				loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
				c.JSON(http.StatusOK, gin.H{
					"status": 1,
					"msg":    "验证码不正确！",
				})
				return
			}
			sendCode, _ := strconv.Atoi(registerCode)
			if parseCode != sendCode {
				c.JSON(http.StatusOK, gin.H{
					"status": 1,
					"msg":    "验证码错误",
				})
				return
			}
		}
	}

	invService := front.Invitations{}
	res, invitation, msg := invService.GetInvitation(invitationCode)

	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    msg,
		})
		return
	} else {
		if invitation.Code != invitationCode {
			c.JSON(http.StatusOK, gin.H{
				"status": 1,
				"msg":    msg,
			})
			return
		}
	}
	err = invService.DeleteInvitation(invitation.Id)
	if err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	}
	//var registerInfo RegisterInfo
	//if c.ShouldBind(&registerInfo) == nil {
	err, user := front.Register(phone, password)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "注册失败" + err.Error(),
		})
		return
	}

	j := &myjwt.JWT{
		SigningKey: []byte("newtrekWang"),
	}
	userId := strconv.Itoa(user.Id)
	claims := myjwt.CustomClaims{
		ID:    userId,
		Name:  user.Username,
		Phone: user.Phone,
		StandardClaims: jwtgo.StandardClaims{
			NotBefore: time.Now().Unix() - 1000,    // 签名生效时间
			ExpiresAt: time.Now().Unix() + 3600*24, // 过期时间 一小时
			Issuer:    "ijiankang",                 //签名的发行者
		},
	}

	token, err := j.CreateToken(claims)

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    err.Error(),
		})
		return
	}

	log.Println(token)

	data := LoginResult{
		Token:    token,
		Avatar:   user.Avatar,
		City:     user.City,
		Country:  user.Country,
		FamilyId: user.FamilyId,
		Gender:   user.Gender,
		Phone:    user.Phone,
		Status:   user.Status,
		Summary:  user.Summary,
		Username: user.Username,
	}

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "注册成功！",
		"data":   data,
	})
	return

}

////ResetPwd 重置密码
//func (Users) ResetPassword(c *gin.Context){
//	db, err := bolt.Open(dbName, 0600, nil)
//	if err != nil {
//		log.Fatal(err)
//	}
//	defer db.Close()
//
//	err = db.Update(func(tx *bolt.Tx) error {
//		bucket := tx.Bucket([]byte(userBucket))
//		if bucket == nil {
//			return fmt.Errorf(" userBuket is null")
//		}
//		c := bucket.Cursor()
//		for k, v := c.First(); k != nil; k, v = c.Next() {
//			userTemp := loadUser(v)
//			if mobile == userTemp.Phone {
//				userTemp.Pwd = pwd
//				return bucket.Put([]byte(userTemp.Id), dumpUser(userTemp))
//			}
//		}
//		return nil
//	})
//	return err
//}

// 生成令牌
func (Users) Login(c *gin.Context) {
	phone := c.PostForm("phone")
	password := c.PostForm("password")
	if phone == "" || password == "" {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "手机号和密码不能为空！",
		})
		return
	}
	if !VerifyMobileFormat(phone) {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "请输入合法的手机号！",
		})
		return
	}
	if !VerifyPwdFormat(password) {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "账号或者密码有误。",
		})
		return
	}

	user, res := front.CheckUser(phone)
	if !res {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    "账号不存在，请先注册。",
		})
		return
	}

	j := &myjwt.JWT{
		SigningKey: []byte("newtrekWang"),
	}
	userId := strconv.Itoa(user.Id)
	claims := myjwt.CustomClaims{
		ID:    userId,
		Name:  user.Username,
		Phone: user.Phone,
		StandardClaims: jwtgo.StandardClaims{
			NotBefore: time.Now().Unix() - 1000,    // 签名生效时间
			ExpiresAt: time.Now().Unix() + 3600*24, // 过期时间 一小时
			Issuer:    "ijiankang",                 //签名的发行者
		},
	}

	token, err := j.CreateToken(claims)

	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": 1,
			"msg":    err.Error(),
		})
		return
	}

	log.Println(token)

	data := LoginResult{
		Token:    token,
		Avatar:   user.Avatar,
		City:     user.City,
		Country:  user.Country,
		FamilyId: user.FamilyId,
		Gender:   user.Gender,
		Phone:    user.Phone,
		Status:   user.Status,
		Summary:  user.Summary,
		Username: user.Username,
	}
	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "登录成功！",
		"data":   data,
	})
	return
}

// GetDataByTime 一个需要token认证的测试接口
func GetDataByTime(c *gin.Context) {
	claims := c.MustGet("claims").(*myjwt.CustomClaims)
	if claims != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": 0,
			"msg":    "token有效",
			"data":   claims,
		})
		return
	}
	return
}
